acme.sh 自动管理 ssl 证书
Table of Contents
1. 安装 acme.sh
1.1. Linux
acme.sh 可以以 root 用户身份进行操作,也可以以普通用户身份进行操作。推荐以普通用户身份安装。
切换到 root 用户或者普通用户执行 curl https://get.acme.sh | sh
之后等待。
目录 ~/.acme.sh 内包含程序的所有文件。删除 acme.sh 只需要删除这个文件夹与 crontab 中的 acme.sh 任务即可。
启用日志需要在 ~/.acme.sh/account.conf 文件中加入
LOG_FILE="/home/<username>/.acme.sh/acme.sh.log"
1.2. FreeBSD
执行 pkg install acme.sh
后,系统会自动创建 acme
用户和 acme
用户组,家目录为 /var/db/acme,申请的证书会被放在 /var/db/acme/certs 下。
/var/db/acme/.acme.sh/account.conf
中日志配置为 LOG_FILE='/var/log/acme.sh.log'
,但 acme 用户和用户组没有 /var/log 目录的读写权限,所以在申请证书过程中会报错。
把日志配置修改为 LOG_FILE='/var/db/acme/acme.sh.log'
让日志直接写在 acme 用户的家目录下就正常了。
定期更新证书的 crontab 任务需要用户自行添加,而 Linux 上的在安装 acme.sh 时就已经完成了。
以 root 权限执行 sudo crontab -e -u acme
用编辑器添加 cron 任务:
0 18 * * * /usr/local/sbin/acme.sh --cron --home /var/db/acme/.acme.sh > /dev/null
2. 迁移 acme.sh
2.1. Linux
主要迁移两个部分: ~/.acme.sh 和 crontab 定时任务。下面以用户间迁移为例,主机间迁移步骤相同。
如果开始以 root 安装了 acme.sh 但是想迁移到其他用户下,需要如下操作:
- 移动程序目录
sudo mv /root/.acme.sh/ ~
- 修改程序目录权限
sudo chown -R <username>:<user_group> ~/.acme.sh
- 修改 acme.sh 环境变量,在 ~/.acme.sh/acme.sh.env 文件中:
- LE_WORKING 对应的路径改成
/home/<username>/.acme.sh
- alias 对应的路径改成
/home/<username>/.acme.sh/acme.sh
- LE_WORKING 对应的路径改成
- 设置定时任务,执行
crontab -e
输入任务36 0 * * * "/home/<username>/.acme.sh"/acme.sh --cron --home "/home/<username>/.acme.sh" > /dev/null
/root/.bashrc
文件里面如果还残留有. "/root/.acme.sh/acme.sh.env"
,删掉即可。- 切换到 root 用户执行
crontab -e
删除该用户下的定时任务。
至此,主体迁移完成。
如果打开了日志也需要更改 ~/.acme.sh/account.conf 文件中的日志路径。
2.2. FreeBSD
先 tar zcf acme.tar.gz /var/db/acme
打包旧系统上 acme 用户的家目录,然后 crontab -l -u acme
备份 acme 用户的 cron 任务。
然后在新系统上 pkg install acme.sh
安装 acme 后,用 acme.tar.gz 里面的内容覆盖 /var/db/acme 中的内容。
最后在新系统上 sudo crontab -e -u acme
为 acme 用户添加 cron 任务以自动更新证书。
3. 申请证书
从 2021.08.01,也就是 acme.sh 3.0 开始,证书颁发机构被切换到了 ZeroSSL。
申请证书可以用 http 验证或者 DNS 验证。其中 DNS 验证方式需要手动操作,但是,以 DNS Api 的方式进行验证可以实现自动续期。
下面是 DNS Api 的操作方法。
3.1. 内网机器
以阿里云为例。
登陆阿里云控制台 -> 企业 -> 人员权限管理 -> 访问控制 RAM - 人员管理 - 用户 -> 创建用户 -> 勾选 编程访问 。
保存生成的 AccessKey 信息,这个信息只展示一次。
进入用户页面 -> 权限管理 -> 添加权限 -> 添加 AliyunDNSFullAccess 权限后保存。
根据官方 DNS Api 获取阿里云环境变量格式并填入对应的字符串,然后导入环境变量:
export Ali_Key="LTAI4Fd8J9qs4fxxxxxxxxxx"
export Ali_Secret="Xp3Z7NDOW0CJcPLKoUwqxxxxxxxxxx"
执行 acme.sh --issue --server zerossl --dns dns_ali -d lishouzhong.com -d "*.lishouzhong.com" --dnssleep 600
申请证书。
注意: --dnssleep 600
不能少。acme.sh 在添加 _acme-challenge
之后会用 CloudFlare 或者 google 的公开 DNS 进行验证。但我们的大内网并不能使用这两家的服务。所以需要这个参数让 acme.sh 等待 600s 之后直接使用物理机指定的 DNS 进行验证。这样才能验证成功。
3.2. 外网机器
以 CloudFlare 为例。
登陆 Cloudflare 控制台,点击域名,在 Overview 选项对应页面的右下角找到 Account ID ,它是环境变量 CF_Account_ID
的值。
然后点击 Account ID 下的 Get your API token -> API Token -> Create Token -> 找到 Custom token 点击 Get Started 。值如下:
- Token name: acme;
- Permissions 选项卡:
- Zone - DNS - Edit ;
- Zone - Zone - Read ;
- Zone Resources 选项卡: Include - All zones from an account - 选择自己的账户邮箱。
创建完成之后保存生成的 API Token ,这串字符只展示一次。它是环境变量 CF_Token
的值。
导入环境变量:
export CF_Token="PfCA6tyLxxxxxxxx-sS6ANgqzuVexxxxxxx"
export CF_Account_ID="1fs48ec7e2063cb70hacc3xxxxxxxxxx"
执行 acme.sh --issue --server zerossl --dns dns_cf -d lishouzhong.com -d "/.lishouzhong.com"
开始申请证书。
4. 安装证书
执行 ~/.acme.sh/acme.sh --list
列出全部证书。
根据官方说法: 不要直接用 ~/.acme.sh/ 目录内的证书文件,因为目录结构可能会因为脚本自动更新而变动。
正确的使用方法是使用 --install-cert
参数,并指定目标位置,然后证书文件会被 copy 到相应的位置,例如:
比如 Apache:
acme.sh --install-cert -d example.com \ --cert-file /path/to/certfile/in/apache/cert.pem \ --key-file /path/to/keyfile/in/apache/key.pem \ --fullchain-file /path/to/fullchain/certfile/apache/fullchain.pem \ --reloadcmd "service apache2 force-reload"
比如 Nginx:
acme.sh --install-cert -d example.com \ --key-file /path/to/keyfile/in/nginx/key.pem \ --fullchain-file /path/to/fullchain/nginx/cert.pem \ --reloadcmd "service nginx force-reload"
安装到其他地方也可以:
acme.sh --install-cert -d lishouzhong.com -d "*.lishouzhong.com" \ --key-file /home/<username>/dockerData/ssl/lishouzhong.com/privkey.pem \ --fullchain-file /home/<username>/dockerData/ssl/lishouzhong.com/fullchain.pem \ --reloadcmd "docker exec nginx nginx -s reload"
--install-cert
的详细参数参考: https://github.com/Neilpang/acme.sh#3-install-the-issued-cert-to-apachenginx-etc
这里指定的所有参数都会被记录,将来证书自动更新以后,自动调用。
要修改安装配置,可修改 vim ~/.acme.sh/<domain>/<domain>.conf
文件或直接运行新的安装命令,即可覆盖上一次的配置。
要删除安装配置,可直接运行无参数的安装命令 acme.sh --install-cert -d <domain> -d "*.<domain>"
。
5. 证书操作
5.1. 更新证书
acme.sh 安装时就已经配置好了自动更新,但如果有需要也可以手动更新:
acme.sh --renew -d lishouzhong.com -d "*.lishouzhong.com" --force
5.2. 吊销证书
如果不再使用申请到的证书,可以选择吊销该证书:
acme.sh --revoke -d lishouzhong.com -d "*.lishouzhong.com"
5.3. 删除证书
从 acme.sh 中移除该证书,但并不吊销该证书:
acme.sh --remove -d lishouzhong.com -d "*.lishouzhong.com"
执行证书移除命令后 acme.sh 仅不再执行有关该证书的任务,但证书文件仍然在 ~/.acme.sh/ 路径下,需要用户手动删除。
5.4. ECC证书
目前最常用的密钥交换算法有 RSA 和 ECDHE:
- RSA 历史悠久,兼容性好,但计算较慢;
- ECDHE 使用 ECC 算法,计算速度快,但兼容性较差;
内置 ECDSA 公钥的证书一般被称之为 ECC 证书 ,内置 RSA 公钥的证书称为 RSA 证书 。ECC 算法的计算复杂度远小于 RSA,但却能用更小的密钥长度得到与 RSA 相同的安全等级,一般认为 256 位 ECC Key 在安全性上等同于 3072 位 RSA Key。
所以 ECC 证书不仅体积小,运算速度也更快。但是由于历史原因,它在旧系统的兼容性上存在不少问题,比如 XP 及之前的 Windows 系统都不能原生支持 ( FireFox 除外 )。
acme.sh 也可以申请 ECC 证书,仅需再申请命令中加上 --keylength
参数,操作上并无太大变化。
目前 --keylength
支持以下三类可选长度:
- ec-256 ( 推荐使用 )
- ec-384
- ec-521 ( 不完善 )
执行 acme.sh --issue --server zerossl --dns dns_ali -d lishouzhong.com -d "*.lishouzhong.com" --dnssleep 600 --keylength ec-256
开始申请证书。在 ~/.acme.sh/ 下的生成的存放 ecc 证书文件夹带 _ecc 后缀。
创建证书安装目录 mkdir -p /home/<username>/dockerData/ssl/lishouzhong.com_ecc/
安装命令要加 --ecc
参数:
acme.sh --install-cert -d lishouzhong.com -d "*.lishouzhong.com" --ecc \ --key-file /home/mgz/dockerData/ssl/lishouzhong.com_ecc/privkey.pem \ --fullchain-file /home/mgz/dockerData/ssl/lishouzhong.com_ecc/fullchain.pem \ --reloadcmd "systemctl force-reload nginx"
更新证书加 --ecc
参数: acme.sh --renew -d lishouzhong.com -d "*.lishouzhong.com" --force --ecc
吊销证书加 --ecc
参数: acme.sh --revoke -d lishouzhong.com -d "*.lishouzhong.com" --ecc
移除证书加 --ecc
参数: acme.sh --remove -d lishouzhong.com -d "*.lishouzhong.com" --ecc
6. 踩坑
6.1. Error add txt for domain:_acme-challenge.*
到阿里云的 DNS 解析配置页,或者 CloudFlare 控制台查 DNS 解析记录。
如果以前申请过,有 CNAME 记录没删,手动删掉 _acme-challenge 的 CNAME 再次运行就正常了。
6.2. 卡在 Checking lishouzhong.com for _acme-challenge.*
这个问题一般出在大内网的机器上。
申请证书过程中,acme.sh 在添加 _acme-challenge
之后会用 CloudFlare 或者 google 的公开 DNS 进行验证。但大内网不让用这两家的服务。所以需要加 --dnssleep
这个参数让 acme.sh 等待 600s 之后 ( 600s 在多数时候足以让国外的 DNS 服务器上的信息传导到国内服务器上 ) 直接使用物理机指定的 DNS 进行验证。这样才能验证成功。